﻿using Engine.Graphics;
using SharpDX;
using System.IO;
using System.Runtime.InteropServices;

namespace Cobra11Undercover
{
    internal class C11UCVertex
    {
        #region Public Structs

        [StructLayout(LayoutKind.Explicit)]
        public struct C11UCData : IGameVertex
        {
            [FieldOffset(0)]
            public Vector3 UV;

            [FieldOffset(12)]
            public Vector4 UV2;

            [FieldOffset(28)]
            private Color4 diffuseColor;

            [FieldOffset(44)]
            private Color4 vertexColor;

            public C11UCData(float u1, float v1, float w1, float u2, float v2, float w2, float z2, Color4 vertexColor, Color4 diffuseColor)
            {
                this.UV.X = u1;
                this.UV.Y = v1;
                this.UV.Z = w1;
                this.UV2.X = u2;
                this.UV2.Y = v2;
                this.UV2.Z = z2;
                this.UV2.W = w2;
                this.vertexColor = vertexColor;
                this.diffuseColor = diffuseColor;
            }

            public Color4 DiffuseColor
            {
                get { return this.diffuseColor; }
                set { this.diffuseColor = value; }
            }

            public float Tu
            {
                get { return this.UV.X; }
                set { this.UV.X = value; }
            }

            public float Tv
            {
                get { return this.UV.Y; }
                set { this.UV.Y = value; }
            }

            public float Tu2
            {
                get { return this.UV2.X; }
                set { this.UV2.X = value; }
            }

            public float Tv2
            {
                get { return this.UV2.Y; }
                set { this.UV2.Y = value; }
            }

            public Color4 VertexColor
            {
                get { return this.vertexColor; }
                set { this.vertexColor = value; }
            }

            public static int SizeInBytes()
            {
                return Marshal.SizeOf(typeof(C11UCData));
            }

            public static C11UCData FromStream(BinaryReader br, int Version)
            {
                switch (Version)
                {
                    case 0:
                        return LoadVersion0(br);

                    case 1:
                        return LoadVersion1(br);

                    default:
                        throw new System.Exception("C11 Undercover Vertex could not load Version: " + Version.ToString());
                }
            }

            private static C11UCData LoadVersion0(BinaryReader br)
            {
                C11UCData vertex = new C11UCData();
                // vertex Color
                float vertexColorAlpha = br.ReadSingle(); // 1.0 Shadow -> 0.0 no Shadow
                float vertexColorRed = br.ReadSingle();
                float vertexColorGreen = br.ReadSingle();
                float vertexColorBlue = br.ReadSingle();
                // Diffuse Color
                float diffuseAlpha = br.ReadSingle();
                float diffuseRed = br.ReadSingle();
                float diffuseGreen = br.ReadSingle();
                float diffuseBlue = br.ReadSingle();

                vertex.DiffuseColor = new Color4(diffuseRed, diffuseGreen, diffuseBlue, diffuseAlpha);
                vertex.VertexColor = new Color4(vertexColorRed, vertexColorGreen, vertexColorBlue, 0.0f);

                //vertex.DiffuseColor = new Color4(0.4f, 0.4f, 0.4f, 0.0f);
                //vertex.VertexColor = new Color4(1.0f, 0.4f, 0.4f, 1.0f);

                return vertex;
            }

            private static C11UCData LoadVersion1(BinaryReader br)
            {
                C11UCData vertex = new C11UCData();

                // UV Coordinates
                vertex.Tu = br.ReadSingle();
                vertex.Tv = br.ReadSingle();
                vertex.Tu2 = br.ReadSingle();
                vertex.Tv2 = br.ReadSingle();

                // vertex Color
                float vertexColorAlpha = br.ReadSingle(); // 1.0 Shadow -> 0.0 no Shadow
                float vertexColorRed = br.ReadSingle();
                float vertexColorGreen = br.ReadSingle();
                float vertexColorBlue = br.ReadSingle();
                // Diffuse Color
                float diffuseAlpha = br.ReadSingle();
                float diffuseRed = br.ReadSingle();
                float diffuseGreen = br.ReadSingle();
                float diffuseBlue = br.ReadSingle();

                vertex.DiffuseColor = new Color4(diffuseRed, diffuseGreen, diffuseBlue, diffuseAlpha);
                vertex.VertexColor = new Color4(vertexColorRed, vertexColorGreen, vertexColorBlue, 0.0f);

                //vertex.DiffuseColor = new Color4(0.4f, 0.4f, 0.4f, 0.0f);
                //vertex.VertexColor = new Color4(1.0f, 0.4f, 0.4f, 1.0f);

                return vertex;
            }

            public void ToStream(BinaryWriter bw)
            {
                bw.Write(this.Tu);
                bw.Write(this.Tv);

                bw.Write(this.Tu2);
                bw.Write(this.Tv2);

                bw.Write(this.vertexColor.Alpha);
                bw.Write(this.vertexColor.Red);
                bw.Write(this.vertexColor.Green);
                bw.Write(this.vertexColor.Blue);

                bw.Write(this.DiffuseColor.Alpha);
                bw.Write(this.DiffuseColor.Red);
                bw.Write(this.DiffuseColor.Green);
                bw.Write(this.DiffuseColor.Blue);
            }

            public int GetCurrentVersion()
            {
                // Version 1: 01.02.2017
                return 1;
            }

            public IGameVertex UpdateWithEngineVertexData(Engine.Graphics.VertexStructures.MyOwnVertex.PositionNormalTextured positionNormalTextured)
            {
                //this.UV = new Vector3(positionNormalTextured.UV, 0.0f);
                return this;
            }

            public override int GetHashCode()
            {
                return this.UV.GetHashCode() ^ this.UV2.GetHashCode() ^ this.diffuseColor.GetHashCode() ^ this.vertexColor.GetHashCode();
            }
        }

        #endregion Public Structs

        #region Internal Structs

        /// <summary>
        /// complete VertexData. Should only used for scenery export.
        /// </summary>
        internal struct C11UCCompleteVertex
        {
            #region Public Fields

            public C11UCData c11ucVertexData;
            public Engine.Graphics.VertexStructures.MyOwnVertex.PositionNormalTextured engineVertex;

            #endregion Public Fields

            #region Public Constructors

            public C11UCCompleteVertex(Engine.Graphics.VertexStructures.MyOwnVertex.PositionNormalTextured engineVertex,
                C11UCData c11ucVertexData)
            {
                this.engineVertex = engineVertex;
                this.c11ucVertexData = c11ucVertexData;
            }

            public override int GetHashCode()
            {
                unchecked // Overflow is fine, just wrap
                {
                    int hash = 17;
                    hash = hash * 23 + this.c11ucVertexData.GetHashCode();
                    hash = hash * 23 + this.engineVertex.GetHashCode();
                    return hash;
                }
            }

            #endregion Public Constructors
        }

        #endregion Internal Structs
    }
}